﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Web.UI;
using DotNetNuke.Common;
using DotNetNuke.Entities.Modules;

namespace Disgrafic.DNN.SKOWrapper
{
	public class Utils
	{
		public static void LoadSkinObject(TemplateControl control, Control container, Hashtable Settings)
		{
			// if token not configured return
			if (Settings["token"] == null)
				return;

			string key = Settings["token"].ToString();
            SkinControlInfo skoInfo = SkinControlController.GetSkinControlByKey(key);

			// if cannot find skinobject control return
			if (skoInfo == null)
				return;

			Control sko = default(Control);
			sko = control.LoadControl(Globals.ApplicationPath + "/" + skoInfo.ControlSrc);
			// if cannot load skinobject return
			if (sko == null)
				return;

			SetProperties(sko, Settings);
			container.Controls.Add(sko);
		}

		public static Hashtable GetAttributes(Hashtable settings)
		{
			Hashtable attr = new Hashtable();
			// get all the attributes
			foreach (string key in settings.Keys)
			{
				if (key != "token")
					attr.Add(key, settings[key]);
			}

			return attr;
		}

		private static void SetProperties(Control sko, Hashtable Settings)
		{
			// set attribute values
			Hashtable attr = GetAttributes(Settings);
			foreach (string key in attr.Keys)
			{
				SetProperty(sko, key, attr[key].ToString());
			}
		}

		private static void SetProperty(Control sko, string strProperty, string value)
		{
			PropertyInfo pi = null;
			Object o = null;
			pi = sko.GetType().GetProperty(strProperty);
			if (pi != null && TryParse(pi.PropertyType, value, out o))
			{
				pi.SetValue(sko, o, null);
			}
		}

		/// <summary>
		/// Try to convert object <code>value</code> to type <cope>destinationType</code>.
		/// </summary>
		/// <param name="destinationType">Type that the value should be converted to</param>
		/// <param name="value">Object to convert</param>
		/// <param name="parsedValue">Variable to store the converted value</param>
		/// <returns>Parsed object if conversion is possible</returns>
		private static bool TryParse(Type destinationType, object value, out object parsedValue)
		{
			// Assign output value
			parsedValue = null;

			// Resolve strings
			if (destinationType == typeof(string))
			{
				if (value == null)
					parsedValue = null;
				else
					parsedValue = value.ToString();
				return true;
			}

			// Determine is type is nullabre. If so, we can assign null, otherwise use base type.
			if (destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable<>))
			{
				if (value == null)
					return true;
				destinationType = Nullable.GetUnderlyingType(destinationType);
			}

			// If object is null (and the type was not nullable) we cannot convert
			if (value == null)
				return false;

			// Enumerations	
			if (destinationType.IsEnum)
			{
				int num;
				if (int.TryParse(value.ToString(), out num))
				{
					Array values = Enum.GetValues(destinationType);
					int[] arrValues = new int[values.Length];
					values.CopyTo(arrValues, 0);
					int pos = Array.IndexOf(arrValues, num);
					if (pos != -1)
					{
						parsedValue = values.GetValue(pos);
						return true;
					}
				}
				return false;
			}

			// Look is destination type has TryParse method
			MethodInfo meth = destinationType.GetMethod("TryParse", new Type[] { typeof(string), destinationType.MakeByRefType() });
			object[] args;

			if (meth != null)
			{
				// Invoke method and get resulting value
				args = new object[] { value.ToString(), null };
				bool result = (bool)meth.Invoke(destinationType, args);
				if (result)
				{
					parsedValue = args[1];
					return true;
				}
			}

			// Try to convert using TypeConverter
			TypeConverter tc = TypeDescriptor.GetConverter(destinationType);
			if (tc != null)
			{
				if (tc.CanConvertFrom(typeof(string)))
				{
					parsedValue = tc.ConvertFromString(value.ToString());
					return true;
				}
				if (tc.CanConvertFrom(value.GetType()))
				{
					parsedValue = tc.ConvertFrom(value);
					return true;
				}
			}

			// Try to convert using ChangeType
			try
			{
				parsedValue = Convert.ChangeType(value, destinationType);
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
}
